package com.aspire.aimini.service.impl;

import com.aspire.aimini.entity.Tag;
import com.aspire.aimini.repository.TagRepository;
import com.aspire.aimini.service.TagService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 标签服务实现类
 *
 * @author wangguiyou
 * @date 2024-12-19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TagServiceImpl implements TagService {

    private final TagRepository tagRepository;

    /**
     * 创建标签
     *
     * @param tag 标签信息
     * @return 创建的标签
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Tag createTag(Tag tag) {
        log.info("创建标签: {}", tag.getName());

        // 检查标签名称是否已存在
        if (existsByName(tag.getName())) {
            throw new RuntimeException("标签名称已存在: " + tag.getName());
        }

        tag.setCreatedAt(LocalDateTime.now());
        tag.setUpdatedAt(LocalDateTime.now());
        tag.setUsageCount(0);
        tag.setIsDeleted(false);

        tagRepository.insert(tag);
        return tag;
    }

    /**
     * 分页查询标签
     *
     * @param page     页码
     * @param size     每页大小
     * @param category 分类
     * @param keyword  关键词
     * @param isSystem 是否系统标签
     * @return 标签分页结果
     */
    @Override
    public Page<Tag> getTagsPage(int page, int size, String category, String keyword, Boolean isSystem) {
        log.info("分页查询标签: page={}, size={}, category={}, keyword={}, isSystem={}",
                page, size, category, keyword, isSystem);

        Page<Tag> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(Tag::getIsDeleted, false)
                .like(StringUtils.hasText(keyword), Tag::getName, keyword)
                .eq(StringUtils.hasText(category), Tag::getCategory, category)
                .eq(isSystem != null, Tag::getIsSystem, isSystem)
                .orderByDesc(Tag::getUsageCount)
                .orderByDesc(Tag::getCreatedAt);

        return tagRepository.selectPage(pageParam, wrapper);
    }

    /**
     * 根据ID获取标签
     *
     * @param id 标签ID
     * @return 标签信息
     */
    @Override
    public Tag getTagById(Long id) {
        log.info("根据ID获取标签: {}", id);

        Tag tag = tagRepository.selectById(id);
        if (tag == null || tag.getIsDeleted()) {
            throw new RuntimeException("标签不存在: " + id);
        }
        return tag;
    }

    /**
     * 根据名称获取标签
     *
     * @param name 标签名称
     * @return 标签信息
     */
    @Override
    public Tag getTagByName(String name) {
        log.info("根据名称获取标签: {}", name);

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getName, name)
                .eq(Tag::getIsDeleted, false);

        return tagRepository.selectOne(wrapper);
    }

    /**
     * 根据分类获取标签列表
     *
     * @param category 分类
     * @return 标签列表
     */
    @Override
    public List<Tag> getTagsByCategory(String category) {
        log.info("根据分类获取标签列表: {}", category);

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getCategory, category)
                .eq(Tag::getIsDeleted, false)
                .orderByDesc(Tag::getUsageCount)
                .orderByDesc(Tag::getCreatedAt);

        return tagRepository.selectList(wrapper);
    }

    /**
     * 获取热门标签
     *
     * @param limit 数量限制
     * @return 热门标签列表
     */
    @Override
    public List<Tag> getPopularTags(int limit) {
        log.info("获取热门标签: limit={}", limit);

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getIsDeleted, false)
                .gt(Tag::getUsageCount, 0)
                .orderByDesc(Tag::getUsageCount)
                .orderByDesc(Tag::getCreatedAt)
                .last("LIMIT " + limit);

        return tagRepository.selectList(wrapper);
    }

    /**
     * 获取最近使用的标签
     *
     * @param limit 数量限制
     * @return 最近使用的标签列表
     */
    @Override
    public List<Tag> getRecentTags(int limit) {
        log.info("获取最近使用的标签: limit={}", limit);

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getIsDeleted, false)
                .isNotNull(Tag::getLastUsedAt)
                .orderByDesc(Tag::getLastUsedAt)
                .last("LIMIT " + limit);

        return tagRepository.selectList(wrapper);
    }

    /**
     * 获取系统标签
     *
     * @return 系统标签列表
     */
    @Override
    public List<Tag> getSystemTags() {
        log.info("获取系统标签");

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getIsSystem, true)
                .eq(Tag::getIsDeleted, false)
                .orderByAsc(Tag::getName);

        return tagRepository.selectList(wrapper);
    }

    /**
     * 获取自定义标签
     *
     * @return 自定义标签列表
     */
    @Override
    public List<Tag> getCustomTags() {
        log.info("获取自定义标签");

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getIsSystem, false)
                .eq(Tag::getIsDeleted, false)
                .orderByDesc(Tag::getUsageCount)
                .orderByDesc(Tag::getCreatedAt);

        return tagRepository.selectList(wrapper);
    }

    /**
     * 获取未使用的标签
     *
     * @return 未使用的标签列表
     */
    @Override
    public List<Tag> getUnusedTags() {
        log.info("获取未使用的标签");

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getIsDeleted, false)
                .eq(Tag::getUsageCount, 0)
                .orderByDesc(Tag::getCreatedAt);

        return tagRepository.selectList(wrapper);
    }

    /**
     * 更新标签
     *
     * @param tag 标签信息
     * @return 更新后的标签
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Tag updateTag(Tag tag) {
        log.info("更新标签: {}", tag.getId());

        Tag existingTag = getTagById(tag.getId());

        // 如果名称发生变化，检查新名称是否已存在
        if (!existingTag.getName().equals(tag.getName()) && existsByName(tag.getName())) {
            throw new RuntimeException("标签名称已存在: " + tag.getName());
        }

        tag.setUpdatedAt(LocalDateTime.now());
        tagRepository.updateById(tag);

        return getTagById(tag.getId());
    }

    /**
     * 删除标签
     *
     * @param id 标签ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTag(Long id) {
        log.info("删除标签: {}", id);

        Tag tag = getTagById(id);

        // 系统标签不能删除
        if (tag.getIsSystem()) {
            throw new RuntimeException("系统标签不能删除");
        }

        LambdaUpdateWrapper<Tag> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Tag::getId, id)
                .set(Tag::getIsDeleted, true)
                .set(Tag::getUpdatedAt, LocalDateTime.now());

        tagRepository.update(null, wrapper);
    }

    /**
     * 批量删除标签
     *
     * @param ids 标签ID列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTags(List<Long> ids) {
        log.info("批量删除标签: {}", ids);

        if (ids == null || ids.isEmpty()) {
            return;
        }

        // 检查是否包含系统标签
        LambdaQueryWrapper<Tag> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.in(Tag::getId, ids)
                .eq(Tag::getIsSystem, true)
                .eq(Tag::getIsDeleted, false);

        long systemTagCount = tagRepository.selectCount(checkWrapper);
        if (systemTagCount > 0) {
            throw new RuntimeException("不能删除系统标签");
        }

        LambdaUpdateWrapper<Tag> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(Tag::getId, ids)
                .set(Tag::getIsDeleted, true)
                .set(Tag::getUpdatedAt, LocalDateTime.now());

        tagRepository.update(null, wrapper);
    }

    /**
     * 增加标签使用次数
     *
     * @param id 标签ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void incrementUsageCount(Long id) {
        log.info("增加标签使用次数: {}", id);

        LambdaUpdateWrapper<Tag> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Tag::getId, id)
                .setSql("usage_count = usage_count + 1")
                .set(Tag::getLastUsedAt, LocalDateTime.now())
                .set(Tag::getUpdatedAt, LocalDateTime.now());

        tagRepository.update(null, wrapper);
    }

    /**
     * 减少标签使用次数
     *
     * @param id 标签ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void decrementUsageCount(Long id) {
        log.info("减少标签使用次数: {}", id);

        LambdaUpdateWrapper<Tag> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Tag::getId, id)
                .setSql("usage_count = GREATEST(usage_count - 1, 0)")
                .set(Tag::getUpdatedAt, LocalDateTime.now());

        tagRepository.update(null, wrapper);
    }

    /**
     * 搜索标签
     *
     * @param keyword 关键词
     * @param limit   数量限制
     * @return 标签列表
     */
    @Override
    public List<Tag> searchTags(String keyword, int limit) {
        log.info("搜索标签: keyword={}, limit={}", keyword, limit);

        if (!StringUtils.hasText(keyword)) {
            return Collections.emptyList();
        }

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getIsDeleted, false)
                .and(w -> w.like(Tag::getName, keyword)
                        .or().like(Tag::getDescription, keyword))
                .orderByDesc(Tag::getUsageCount)
                .orderByDesc(Tag::getCreatedAt)
                .last("LIMIT " + limit);

        return tagRepository.selectList(wrapper);
    }

    /**
     * 清理未使用的标签
     *
     * @param days 天数阈值
     * @return 清理的标签数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cleanupUnusedTags(int days) {
        log.info("清理未使用的标签: days={}", days);

        LocalDateTime threshold = LocalDateTime.now().minusDays(days);

        LambdaQueryWrapper<Tag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Tag::getIsDeleted, false)
                .eq(Tag::getIsSystem, false)
                .eq(Tag::getUsageCount, 0)
                .lt(Tag::getCreatedAt, threshold);

        List<Tag> unusedTags = tagRepository.selectList(queryWrapper);

        if (!unusedTags.isEmpty()) {
            List<Long> ids = unusedTags.stream()
                    .map(Tag::getId)
                    .collect(Collectors.toList());

            LambdaUpdateWrapper<Tag> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.in(Tag::getId, ids)
                    .set(Tag::getIsDeleted, true)
                    .set(Tag::getUpdatedAt, LocalDateTime.now());

            tagRepository.update(null, updateWrapper);
        }

        return unusedTags.size();
    }

    /**
     * 获取标签分类列表
     *
     * @return 分类列表
     */
    @Override
    public List<String> getCategories() {
        log.info("获取标签分类列表");

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Tag::getCategory)
                .eq(Tag::getIsDeleted, false)
                .isNotNull(Tag::getCategory)
                .ne(Tag::getCategory, "")
                .groupBy(Tag::getCategory)
                .orderByAsc(Tag::getCategory);

        List<Tag> tags = tagRepository.selectList(wrapper);
        return tags.stream()
                .map(Tag::getCategory)
                .filter(StringUtils::hasText)
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 按分类统计标签数量
     *
     * @return 分类统计结果
     */
    @Override
    public Map<String, Long> getTagCountByCategory() {
        log.info("按分类统计标签数量");

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Tag::getCategory)
                .eq(Tag::getIsDeleted, false)
                .isNotNull(Tag::getCategory)
                .ne(Tag::getCategory, "");

        List<Tag> tags = tagRepository.selectList(wrapper);

        return tags.stream()
                .collect(Collectors.groupingBy(
                        tag -> StringUtils.hasText(tag.getCategory()) ? tag.getCategory() : "未分类",
                        Collectors.counting()));
    }

    /**
     * 获取标签使用统计
     *
     * @return 使用统计结果
     */
    @Override
    public Map<String, Object> getUsageStatistics() {
        log.info("获取标签使用统计");

        Map<String, Object> statistics = new HashMap<>();

        // 总标签数
        LambdaQueryWrapper<Tag> totalWrapper = new LambdaQueryWrapper<>();
        totalWrapper.eq(Tag::getIsDeleted, false);
        long totalCount = tagRepository.selectCount(totalWrapper);
        statistics.put("totalCount", totalCount);

        // 系统标签数
        LambdaQueryWrapper<Tag> systemWrapper = new LambdaQueryWrapper<>();
        systemWrapper.eq(Tag::getIsDeleted, false)
                .eq(Tag::getIsSystem, true);
        long systemCount = tagRepository.selectCount(systemWrapper);
        statistics.put("systemCount", systemCount);

        // 自定义标签数
        statistics.put("customCount", totalCount - systemCount);

        // 未使用标签数
        LambdaQueryWrapper<Tag> unusedWrapper = new LambdaQueryWrapper<>();
        unusedWrapper.eq(Tag::getIsDeleted, false)
                .eq(Tag::getUsageCount, 0);
        long unusedCount = tagRepository.selectCount(unusedWrapper);
        statistics.put("unusedCount", unusedCount);

        // 分类数量
        List<String> categories = getCategories();
        statistics.put("categoryCount", categories.size());

        return statistics;
    }

    /**
     * 批量创建标签
     *
     * @param tags 标签列表
     * @return 创建的标签列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Tag> createTags(List<Tag> tags) {
        log.info("批量创建标签: {}", tags.size());

        if (tags == null || tags.isEmpty()) {
            return Collections.emptyList();
        }

        // 检查重复名称
        Set<String> names = tags.stream()
                .map(Tag::getName)
                .collect(Collectors.toSet());

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Tag::getName, names)
                .eq(Tag::getIsDeleted, false);

        List<Tag> existingTags = tagRepository.selectList(wrapper);
        Set<String> existingNames = existingTags.stream()
                .map(Tag::getName)
                .collect(Collectors.toSet());

        List<Tag> newTags = tags.stream()
                .filter(tag -> !existingNames.contains(tag.getName()))
                .collect(Collectors.toList());

        if (newTags.isEmpty()) {
            return Collections.emptyList();
        }

        LocalDateTime now = LocalDateTime.now();
        newTags.forEach(tag -> {
            tag.setCreatedAt(now);
            tag.setUpdatedAt(now);
            tag.setUsageCount(0);
            tag.setIsDeleted(false);
        });

        // 批量插入
        for (Tag tag : newTags) {
            tagRepository.insert(tag);
        }

        return newTags;
    }

    /**
     * 合并标签
     *
     * @param sourceId 源标签ID
     * @param targetId 目标标签ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mergeTags(Long sourceId, Long targetId) {
        log.info("合并标签: sourceId={}, targetId={}", sourceId, targetId);

        if (sourceId.equals(targetId)) {
            throw new RuntimeException("不能合并相同的标签");
        }

        Tag sourceTag = getTagById(sourceId);
        Tag targetTag = getTagById(targetId);

        // 系统标签不能被合并
        if (sourceTag.getIsSystem()) {
            throw new RuntimeException("系统标签不能被合并");
        }

        // 更新目标标签的使用次数
        LambdaUpdateWrapper<Tag> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Tag::getId, targetId)
                .setSql("usage_count = usage_count + " + sourceTag.getUsageCount())
                .set(Tag::getUpdatedAt, LocalDateTime.now());

        tagRepository.update(null, updateWrapper);

        // 删除源标签
        deleteTag(sourceId);
    }

    /**
     * 检查标签名称是否存在
     *
     * @param name 标签名称
     * @return 是否存在
     */
    @Override
    public boolean existsByName(String name) {
        log.debug("检查标签名称是否存在: {}", name);

        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Tag::getName, name)
                .eq(Tag::getIsDeleted, false);

        return tagRepository.selectCount(wrapper) > 0;
    }
}